﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://wpfimageviewer.codeplex.com
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using BrainTechLLC;
using BrainTechLLC.ThreadSafeObjects;
using BrainTechLLC.WPF;
using DragDropLibrary;
using ImageAppDataModels;
using ImageAppViewModels;
using BrainTechLLC.ImageOperatorsNonAForgeDependent;
using BrainTechLLC.ImageOperators;
using BrainTechLLC.FolderExplorer;
using TemporalFilterExtensions;
using System.Drawing;
using System.Windows.Media;
using BrainTechLLC.FilterExtensions;
using System.Windows.Data;
using System.Collections.ObjectModel;
using System.Reflection;
using System.ComponentModel;
using System.Diagnostics;
using VirtualizingTilePanelSample;

namespace WpfImageDuplicates
{
    /// <summary>
    /// Interaction logic for ImageCollectionView.xaml
    /// </summary>
    public partial class ImageCollectionView : UserControl
    {
        public bool _FirstDisplayed;
        public SimpleDispatcherTimer Timer;
        public List<System.Windows.Shapes.Rectangle> Rectangles = new List<System.Windows.Shapes.Rectangle>();
        public event EventHandler<ObjectEventArgsNonRef<FileImageViewModel, bool>> RequestDelete;
        public event EventHandler<ObjectEventArgs<List<FileImageViewModel>>> RequestDeleteMany;
        public event EventHandler<ObjectEventArgsNonRef<FileImageViewModel, bool>> RequestResizeDelete;
        public event EventHandler<ObjectEventArgsNonRef<FileImageViewModel, bool>> RequestResize;
        public event EventHandler<ObjectEventArgsNonRef<RotationParams, bool>> RequestRotate;
        public bool ViewModelCollectionChanged;
        public bool ItemSelectionChanged;
        protected string _lastSort;
        protected string _lastSort2;
        protected ListSortDirection _lastDirection;
        protected ListSortDirection _lastDirection2;
        protected FastSmartWeakEvent<EventHandler<ObjectEventArgs<FileImageViewModel>>> _wantView = new FastSmartWeakEvent<EventHandler<ObjectEventArgs<FileImageViewModel>>>();
        public event EventHandler<ObjectEventArgs<FileImageViewModel>> WantView { add { _wantView.Add(value); } remove { _wantView.Remove(value); } }
        public SimpleTimer _dirtyTimer;
        public bool _needForceRefresh;
        protected bool _needsSetResized;
        public ThumbnailImageCollectionHandler ThumbsHandler;
        public VirtualizingTilePanel _wrapPanel;
        public FileImageCollectionTimer UpdateTimer;
        public FileImageCollectionScrollHandler ScrollHandler;
        public FileImageComparisonHandler ComparisonHandler;
        public FileImageBlurHandler BlurHandler;
        public FileImageCollectionViewModel _vm;
        public bool _resized;
        public object _lockObject = new object();
        public bool _forceRefresh;
        public FileImageViewModel _lastSelected;
        public int _endLocation;
        public int _startLocation;
        public FileImageViewModelCollection Displayed;
        public object _displayedLock = new object();
        public ThreadSafeLookupNonRef<string, bool> DisplayedAlready = new ThreadSafeLookupNonRef<string, bool>();
        public int _lastCount;
        public DirectoryToExamine DirectoryToExamine;
        public int _Columns;
        public int _Rows;
        public SimpleDispatcherTimer _moveTimer;

        public bool ForceRefresh
        {
            get { return _forceRefresh; }
            set
            {
                if (value == true)
                {
                    MarkThumbsDirty();
                }
                _forceRefresh = value;
            }
        }

        public ImageCollectionView()
        {
            InitializeComponent();
            ThumbsHandler = new ThumbnailImageCollectionHandler(this);
            Loaded += new RoutedEventHandler(ImageCollectionView_Loaded);
            lstItems.SizeChanged += new SizeChangedEventHandler(lstItems_SizeChanged);
            Displayed = new FileImageViewModelCollection();
        }

        void ImageCollectionView_Loaded(object sender, RoutedEventArgs e)
        {            
            SimpleDispatcherTimer loadTimer = new SimpleDispatcherTimer(100, tmr =>
            {
                var sv = this.lstItems.GetAllChildren<ScrollViewer>(true);
                if (sv.Count > 0)
                {
                    ScrollHandler = new FileImageCollectionScrollHandler(this);
                    UpdateTimer = new FileImageCollectionTimer(this, ScrollHandler);
                    ComparisonHandler = new FileImageComparisonHandler(this);
                    BlurHandler = new FileImageBlurHandler(this);
                    _dirtyTimer = new SimpleTimer(5000, 3000, timer => SimpleTimerTick(timer));  // was 2700
                    _addTimer = new SimpleTimer(2000, 40, timer => AddTimerTick(timer));
                    _moveTimer = new SimpleDispatcherTimer(1200, timer => MoveTimerTick(timer));
                    _OrderedFileNames = Settings.Values.OrderedFileNames;
                    _moveTimer.Start();
                    return RunInitializationResult.DisposeTimer;
                }
                else
                {
                    return RunInitializationResult.DidntDoAnything;
                }
            });
            loadTimer.Start();
        }

        void viewModel_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (FileImageCollectionViewModel.Count != _lastCount)
            {
                _lastCount = FileImageCollectionViewModel.Count;
                if (!_FirstDisplayed)
                {
                    loadingGrid.Visibility = System.Windows.Visibility.Visible;
                }
            }
        }

        void Values_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName != null && (e.PropertyName.StartsWith("SortBy") || e.PropertyName.StartsWith("SortDescending") || e.PropertyName.StartsWith("SortBy2") || e.PropertyName.StartsWith("SortDescending2")))
            {
                SortAll(true);
            }
        }

        void FileImageCollectionViewModel_ClearingAll(object sender, EventArgs e)
        {
            var allThumbs = ThumbsHandler.GetAllThumbnailViews();

            for (int n = 0; n < allThumbs.Count; n++)
            {
                allThumbs[n]._noGood = true;
            }

            ThumbsHandler.ThumbnailViewsLast = new List<ThumbnailView>();
            ThumbsHandler._thumbsByFileName.Clear();
            //Displayed.Clear(); // HEREHERE
        }

        public List<FileImageViewModel> GetSelectedImages()
        {
            // Select all "Marked" images
            FileImageCollectionViewModel.ForEach(vm =>
            {
                if (vm.SelectedByUser && !vm.IsSelected)
                {
                    vm.IsSelected = true;
                }
            });

            return lstItems.GetSelected<FileImageViewModel>();
        }

        public int IndexOf(FileImageViewModel vm)
        {
            if (vm != null)
            {
                return Displayed.GetIndex(vm.FileName);
            }

            return -1;
        }

        public bool Contains(FileImageViewModel vm)
        {
            return IndexOf(vm) >= 0;
        }

        protected void FileImageCollectionViewModel_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            ViewModelCollectionChanged = true;
            Window1.MainWindow.FileImageCollectionViewModels.ViewModelCollectionChanged = true;
            Window1.MainWindow.CollectionViews.ViewModelCollectionChanged = true;

            try
            {
                switch (e.Action)
                {
                    case NotifyCollectionChangedAction.Add:
                        AddListItem(e.NewItems[0] as FileImageViewModel);
                        break;
                    case NotifyCollectionChangedAction.Remove:
                        RemoveListItem(e.OldItems[0] as FileImageViewModel);
                        break;
                    case NotifyCollectionChangedAction.Reset:
                        ClearListItems();
                        AddListItems(FileImageCollectionViewModel.ToList());
                        break;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        void FileImageCollectionViewModel_WantRefreshDirectories(object sender, EventArgs e)
        {
            ForceRefresh = true;
        }

        void FileImageCollectionViewModel_ThumbnailsInvalidated(object sender, EventArgs e)
        {
            ForceRefresh = true;
        }

        protected RunInitializationResult SimpleTimerTick(SimpleTimer timer)
        {
            ViewModelCollectionChanged = true;
            Window1.MainWindow.FileImageCollectionViewModels.ViewModelCollectionChanged = true;
            Window1.MainWindow.CollectionViews.ViewModelCollectionChanged = true;

            if (_needForceRefresh)
            {
                _needForceRefresh = false;
                _forceRefresh = true;
                if (_wrapPanel != null && _wrapPanel.ActualWidth > 0 && _wrapPanel.ActualHeight > 0)
                {
                    CalculateColumnsAndRows();
                }
            }

            if (_needsSetResized)
            {
                _needsSetResized = false;
                _resized = true;
                if (_wrapPanel != null && _wrapPanel.ActualWidth > 0 && _wrapPanel.ActualHeight > 0)
                {
                    CalculateColumnsAndRows();                    
                }
            }

            return RunInitializationResult.ContinueTimer;
        }

        private void CalculateColumnsAndRows()
        {
            _Columns = (int)Math.Floor((_wrapPanel.ActualWidth / Convert.ToDouble(Settings.Values.ThumbWidthPlus)));
            _Rows = (int)Math.Floor((_wrapPanel.ActualHeight / Convert.ToDouble(Settings.Values.ThumbHeightPlus)));
        }

        public int CalcColumnsPerRow()
        {
            return (int)Math.Floor(this._wrapPanel.ActualWidth / Settings.Values.ThumbWidthPlus);
        }

        protected void thumbnailView_WantView(object sender, ObjectEventArgs<FileImageViewModel> args)
        {
            _wantView.Raise(this, args);
        }

        public void DoForSelected(Action<FileImageViewModel> a)
        {
            var sel = GetSelectedImages();

            if (sel.Count > 0)
            {
                foreach (var item in sel)
                {
                    a(item);
                }
            }
        }

        void lstItems_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            _needsSetResized = true;
        }

        private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            _needsSetResized = true;
        }

        private void WrapPanel_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Q)
            {
                if (lstItems.SelectedItem != null)
                {
                    FileImageViewModel vm = lstItems.SelectedItem as FileImageViewModel;
                    ThumbnailView tv = FindThumbView(vm);
                    if (tv != null)
                    {
                        ThumbsHandler.WantRotateSelectedCounterClockwise(tv);
                        e.Handled = true;
                    }
                }
            }
            else if (e.Key == Key.W)
            {
                if (lstItems.SelectedItem != null)
                {
                    FileImageViewModel vm = lstItems.SelectedItem as FileImageViewModel;
                    ThumbnailView tv = FindThumbView(vm);
                    if (tv != null)
                    {
                        ThumbsHandler.WantRotateSelectedClockwise(tv);
                        e.Handled = true;
                    }
                }
            }
            else if (e.Key == Key.R)
            {
                // Here
            }
            else if (e.Key == Key.OemMinus)
            {
                if (lstItems.SelectedItem != null)
                {
                    FileImageViewModel vm = lstItems.SelectedItem as FileImageViewModel;
                    ThumbnailView tv = FindThumbView(vm);
                    if (tv != null)
                    {
                        ThumbsHandler.WantResizeDelete(tv, vm.LastOriginalBitmapWidth, vm.LastOriginalBitmapHeight);
                        e.Handled = true;
                    }
                }
            }
            //else if (e.Key == Key.M)
            //{
            //    if (lstItems.SelectedItem != null)
            //    {
            //        FileImageViewModel vm = lstItems.SelectedItem as FileImageViewModel;
            //        ThumbsHandler.MasterImage = vm;
            //        e.Handled = true;
            //    }
            //}
            //else if (e.Key == Key.N)
            //{
            //    if (ThumbsHandler.MasterImage != null)
            //    {
            //        if (lstItems.SelectedItem != null)
            //        {
            //            FileImageViewModel vm = lstItems.SelectedItem as FileImageViewModel;
            //            e.Handled = true;
            //            var original = ThumbsHandler.MasterImage.FileImage.EnsureBitmapLoaded();
            //            var comparison = vm.FileImage.EnsureBitmapLoaded();

            //            if (original.Width != comparison.Width || original.Height != comparison.Height)
            //            {
            //                MessageBox.Show("Cannot do this - different widths/heights");
            //                return;
            //            }

            //            var filter = new AForge.Imaging.Filters.DifferenceCalc(comparison);
            //            Bitmap bmDiff = filter.Apply(original);
            //            int countOfZeroDifference = 0;
            //            int maxY = filter._resultDifferences.GetUpperBound(0);
            //            int maxX = filter._resultDifferences.GetUpperBound(1);
            //            int totalDiff = 0;
            //            for (int y = 0; y < maxY; y++)
            //            {
            //                for (int x = 0; x < maxX; x++)
            //                {
            //                    int diff = filter._resultDifferences[y, x];
            //                    if (diff == 0)
            //                        countOfZeroDifference++;
            //                    else
            //                        totalDiff += Math.Abs(diff);
            //                }
            //            }
            //            string msg = string.Format("Total: {0}, Zero Diffs: {1}, Absolute Diffs: {2}, Percent Zero Diffs: {3}", maxX * maxY, countOfZeroDifference, totalDiff,
            //                (countOfZeroDifference * 100) / (maxX * maxY));

            //            MessageBox.Show(msg);
            //        }
            //    }
            //}
            if (HandlePageUpDown(e.Key, e.KeyboardDevice.Modifiers))
            {
                e.Handled = true;
            }
            else if (e.Key == Key.Enter)
            {
                if (_wantView != null)
                {
                    _wantView.Raise(this, new ObjectEventArgs<FileImageViewModel>(_lastSelected));
                }
            }
        }

        private void lstItems_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            lstItems.SelectionChanged -= lstItems_SelectionChanged;

            try
            {
                if (e.AddedItems != null)
                {
                    foreach (var item in e.AddedItems)
                    {
                        FileImageViewModel vm = item as FileImageViewModel;
                        vm.SilentSetIsSelected(true);
                    }
                }

                if (e.RemovedItems != null)
                {
                    foreach (var item in e.RemovedItems)
                    {
                        FileImageViewModel vm = item as FileImageViewModel;
                        vm.SilentSetIsSelected(false);
                    }
                }

                if (lstItems.SelectedItem != null)
                {
                    _lastSelected = lstItems.SelectedItem as FileImageViewModel;
                }

                _vm.Where(vm => vm.SelectedByUser).ForEach(vm => lstItems.SelectedItems.Add(vm));

                ItemSelectionChanged = true;
                Window1.MainWindow.CollectionViews.ItemSelectionChanged = true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            finally
            {
                lstItems.SelectionChanged += new SelectionChangedEventHandler(lstItems_SelectionChanged);
            }
        }

        private void mnuDifferenceFilter_Click(object sender, RoutedEventArgs e)
        {
            DoDifference();
        }

        private void DoDifference()
        {
            var sel = GetSelectedImages();
            if (sel.Count >= 2)
            {
                imgView.Visibility = Visibility.Visible;

                try
                {
                    DifferenceFilterCompareTwo d = new DifferenceFilterCompareTwo()
                    {
                    };
                    var thumb1 = sel[sel.Count - 2].Thumbnail;
                    var thumb2 = sel[sel.Count - 1].Thumbnail;
                    Bitmap bm = d.Apply(thumb1, thumb2);
                    ImageSource imgSource = bm.CreateImageSourceFromBitmap(null);
                    testImage.Source = imgSource;
                    ImageCalculation calc = new ImageCalculation("Color Calc", (a, b, c, z) => ImageCalculation.SumColors(a, b, c, z));
                    var result = calc.Calculate(bm);
                    var orig1 = calc.Calculate(thumb1);
                    var orig2 = calc.Calculate(thumb2);
                    double d1 = orig1.GetTotalResult();
                    double d2 = orig2.GetTotalResult();
                    result.Result *= 10000000;
                    result.Result /= (d1 + d2);
                    //mnuResults.Header = result.ToString() + " : " + d1.ToString("N0") + "/" + d2.ToString("N0");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
            else
            {
                imgView.Visibility = Visibility.Collapsed;
            }
        }

        //private void thumbnailView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        //{
        //    ThumbnailView tv = sender as ThumbnailView;
        //    tv.IsSelected = true;
        //}

        private void thumbnailView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            ThumbnailView tv = sender as ThumbnailView;
            tv.IsSelected = true;
        }

        public void ClearSelected()
        {
            lstItems.SelectedItems.Clear();
            Displayed.ForEach(vm => vm.IsSelected = false);
        }

        private void itemsPanel_Loaded(object sender, RoutedEventArgs e)
        {
            _wrapPanel = sender as VirtualizingTilePanel;
            _wrapPanel.CollectionParent = this;
            Binding b1 = new Binding() { Path = new PropertyPath("ThumbWidthPlus"), Source = Settings.Values, Mode = BindingMode.OneWay };
            _wrapPanel.SetBinding(VirtualizingTilePanel.ChildSizeXProperty, b1);
            Binding b2 = new Binding() { Path = new PropertyPath("ThumbHeightPlus"), Source = Settings.Values, Mode = BindingMode.OneWay };
            _wrapPanel.SetBinding(VirtualizingTilePanel.ChildSizeYProperty, b2);
        }


        private void thumbView_Loaded(object sender, RoutedEventArgs e)
        {
            if (!_FirstDisplayed)
            {
                _FirstDisplayed = true;
                loadingGrid.Visibility = System.Windows.Visibility.Collapsed;
            }
            ThumbnailView thumb = sender as ThumbnailView;
            thumb.ParentCollectionView = this;
            thumb.ThumbVisible = true;
            ThumbsHandler._thumbsByFileName.Add(thumb._vm.FileName, thumb);
            thumb._vm.Dirty = true;
            CheckThumbnailViewWiring(thumb);
            
            try
            {
                thumb.OnThumbBecomesVisible();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

            if (thumb._vm.IsSelected)
            {
                Dispatcher.BeginInvoke(new VoidDelegate(() =>
                {
                    lstItems.SelectedItems.Add(thumb._vm);
                    BrainTechLLC.WPF.TempExten.FindParent<ListBoxItem>(thumb).Focus();
                }), System.Windows.Threading.DispatcherPriority.Send); // was normal
            }
        }

        private void thumbView_ThumbVisibilityChanged(object sender, EventArgs e)
        {
            ThumbnailView thumb = sender as ThumbnailView;
            CheckThumbnailViewWiring(thumb);
            _WantCleanupOldThumbs = true;
        }

        private void thumbView_SetThumbImage(object sender, EventArgs e)
        {
            ThumbnailView thumb = sender as ThumbnailView;
            if (thumb != null && ThumbsHandler != null)
            {
                ThumbsHandler.NonDirtyThumbs.Add(thumb, thumb);
            }
        }        
    }
}
